#include <iostream>

extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavutil/frame.h>
    #include <libavutil/imgutils.h>
    #include <libavutil/log.h>
}

using namespace std;


int main(int argc, char* argv[]) {
    int ret = 0;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input RTSP URL>\n", argv[0]);
        return -1;
    }

    // const char* inputUrl = "rtsp://192.168.42.1/h264";
    // const char* inputUrl = "rtsp://10.222.222.150:554";

    const char* inputUrl = argv[1];
    AVFormatContext* formatContext = nullptr;
    AVCodecContext* codecContext = nullptr;
    AVCodec* codec = nullptr;
    AVPacket packet;
    AVFrame* frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate frame\n");
        return -1;
    }
    cout << "开始程序~~~\n";
    // 初始化FFmpeg库
    avformat_network_init();
    // 设置日志级别
    av_log_set_level(AV_LOG_DEBUG);

    // 打开输入RTSP流
    cout << "打开RTSP流：" << inputUrl << "\n";
    ret = avformat_open_input(&formatContext, inputUrl, nullptr, nullptr);
    if (ret < 0) {
        char errorBuffer[AV_ERROR_MAX_STRING_SIZE];
        std::cerr << "Could not open input file/url: " << inputUrl << ". Error: " << av_make_error_string(errorBuffer, AV_ERROR_MAX_STRING_SIZE, ret) << std::endl;
        av_frame_free(&frame); // 释放frame
        return -1;
    }

    // 查找流信息
    cout << "查找RTSP流信息\n";
    ret = avformat_find_stream_info(formatContext, nullptr);
    if (ret < 0) {
        char errorBuffer[AV_ERROR_MAX_STRING_SIZE];
        std::cerr << "Could not find stream information. Error: " << av_make_error_string(errorBuffer, AV_ERROR_MAX_STRING_SIZE, ret) << std::endl;
        avformat_close_input(&formatContext);
        return -1;
    }

    // 打印流信息
    cout << "打印相关信息\n";
    av_dump_format(formatContext, 0, inputUrl, 0);


    // 查找视频流
    int videoStreamIndex = -1;
    for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }
    if (videoStreamIndex == -1) {
        fprintf(stderr, "Could not find video stream\n");
        return -1;
    }

    // 获取解码器
    codec = avcodec_find_decoder(formatContext->streams[videoStreamIndex]->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        return -1;
    }

    // 分配解码器上下文
    codecContext = avcodec_alloc_context3(codec);
    if (!codecContext) {
        fprintf(stderr, "Could not allocate video codec context\n");
        return -1;
    }

    // 复制解码器参数到解码器上下文
    if (avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0) {
        fprintf(stderr, "Failed to copy codec parameters to codec context\n");
        return -1;
    }

    // 打开解码器
    if (avcodec_open2(codecContext, codec, nullptr) < 0) {
        fprintf(stderr, "Could not open codec\n");
        return -1;
    }

    // 读取帧并解码
    while (av_read_frame(formatContext, &packet) >= 0) {
        if (packet.stream_index == videoStreamIndex) {
            if (avcodec_send_packet(codecContext, &packet) == 0) {
                while (avcodec_receive_frame(codecContext, frame) == 0) {
                    // 这里处理解码后的帧，例如保存为图片或者显示
                    // frame->data 包含了图像数据
                    // frame->linesize 包含了图像每行的字节大小
                    // 例如，你可以使用SwScale转换图像格式
                    // ...
                    std::cout << "linesize:" << frame->linesize << endl;
                }
            }
        }
        av_packet_unref(&packet);
    }

    // 释放资源
    av_frame_free(&frame);
    avcodec_close(codecContext);
    avformat_close_input(&formatContext);

    return 0;
}

//编译：g++ -o rtsp_decoder rtsp_decoder.cpp $(pkg-config --cflags --libs libavformat libavcodec libavutil)

